//Rim
//Written by MJ_Ehsan for Reshade
//Version 1.0a

//license
//CC0 ^_^

///////////////Include/////////////////////

#include "ReShade.fxh"

#define pix float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);

#if __RENDERER__ < 0xA000
 #define D3D9 0 //yes it's weird to set true value as 0 and false as 1?
#else
 #define D3D9 1
#endif

///////////////Include/////////////////////
///////////////Textures-Samplers///////////

texture TexColor : COLOR;
sampler sTexColor {Texture = TexColor; SRGBTexture = false;};	

texture TexDepth : DEPTH;
sampler sTexDepth {Texture = TexDepth; SRGBTexture = false;};

texture TexRim { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA16f; };
sampler sTexRim {Texture = TexRim; SRGBTexture = false;};	

texture TexHBlur { Width = BUFFER_WIDTH; Height = BUFFER_HEIGHT; Format = RGBA16f; };
sampler sTexHBlur {Texture = TexHBlur; SRGBTexture = false;};

///////////////Textures-Samplers///////////
///////////////UI//////////////////////////

uniform int Blend <
	ui_label = "Blend Mode";
	ui_type = "combo";
	ui_items = "Add\0Color Dodge\0";
> = 0;

uniform float smooth <
	ui_label = "Rim Width";
	ui_type = "slider";
	ui_tooltip = "Higher values limits the rim to a tighter area";
	ui_category = "Rim";
	ui_min = 1;
	ui_max = 10;
> = 5;

uniform float Rim <
	ui_label = "Rim Intensity";
	ui_type = "slider";
	ui_category = "Rim";
	ui_tooltip = "Exposure of the rim";
	ui_min = 0;
	ui_max = 100;
> = 1;

uniform float3 light <
	ui_label = "Rim Light Color";
	ui_category = "Rim";
	ui_type = "color";
> = 1;

#if D3D9
uniform int BLUR_ITERATION_ <
	ui_label = "Bloom Width";
	ui_type = "slider";
	ui_category = "Bloom";
	ui_min = 1;
	ui_max = 16;
> = 4;
#else
#ifndef BLUR_ITERATION_
 #define BLUR_ITERATION_ 4
#endif
#endif
uniform float bloom <
	ui_label = "Bloom Intensity";
	ui_type = "slider";
	ui_category = "Bloom";
	ui_min = 0;
	ui_max = 10;
> = 1;

uniform float MaxDepth <
	ui_label = "Max Depth";
	ui_tooltip = "Depth Masking End Clipping";
	ui_category = "Masking";
	ui_type = "slider";
> = 1;

uniform float MinDepth <
	ui_label = "Min Depth";
	ui_category = "Masking";
	ui_tooltip = "Depth Masking Start Clipping";
	ui_type = "slider";
> = 0;

//static const bool Quality = 0;

///////////////UI//////////////////////////
///////////////Functions///////////////////

float3 Depth(float2 texcoord)
{
	return ReShade::GetLinearizedDepth(texcoord);
}

float3 GetNormal(float2 texcoord)
{
	float3 offset = float3(BUFFER_PIXEL_SIZE, 0.0);
	float2 posCenter = texcoord.xy;
	float2 posNorth  = posCenter - offset.zy;
	float2 posEast   = posCenter + offset.xz;

	float3 vertCenter = float3(posCenter - 0.5, 1) * Depth(posCenter);
	float3 vertNorth  = float3(posNorth  - 0.5, 1) * Depth(posNorth);
	float3 vertEast   = float3(posEast   - 0.5, 1) * Depth(posEast);

	return normalize(cross(vertCenter - vertNorth, vertCenter - vertEast)) * 0.5 + 0.5;
}

float3 GetNormalHQ(float2 texcoord)
{
	float3 p = float3(BUFFER_PIXEL_SIZE, 0.0);
	float3 h;
	float3 v;
	//-|1|-
	//2|5|3
	//-|4|-
	float3 Sample[6];
	Sample[1] = Depth(texcoord + p.zy);// * float3( texcoord + p.zy - 0.5, 1);
	Sample[2] = Depth(texcoord - p.xz);// * float3( texcoord - p.xz - 0.5, 1);
	Sample[3] = Depth(texcoord - p.zy);// * float3( texcoord - p.zy - 0.5, 1);
	Sample[4] = Depth(texcoord + p.xz);// * float3( texcoord + p.xz - 0.5, 1);
	Sample[5] = Depth(texcoord       );// * float3( texcoord        - 0.5, 1);
	
	h = Sample[5] - Sample[3];
	if( dot( 0.333, abs(Sample[5] - Sample[2])) < dot( 0.333, abs(Sample[5] - Sample[3])))
	h = Sample[2] - Sample[5];
		
	v = Sample[5] - Sample[4];
	if( dot( 0.333, abs(Sample[5] - Sample[1])) < dot( 0.333, abs(Sample[5] - Sample[4])))
	v = Sample[1] - Sample[5];
		
	//return normalize(cross(h, v)) * 0.5 + 0.5;
	return float3(h.x,v.x,10) * 0.5 + 0.5;
}
///////////////Functions///////////////////
///////////////Vertex Shader///////////////
///////////////Vertex Shader///////////////
///////////////Pixel Shader////////////////

float3 rim(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
	float2 p = pix;
	float3 normal; normal = GetNormal( texcoord ).z;
	//if(Quality == 0) {normal = GetNormal( texcoord ).z;}
	//else             {normal = GetNormalHQ(texcoord).z;}
	
	float3 color = tex2D(sTexColor, texcoord).rgb;
	
	normal = 1-normal;
	normal = pow(abs(normal), smooth);
	normal *= Rim;
	
	color = normal * color * (light);
	color = color/(color+1);
	return color;
}

float3 HBlur(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
	float2 p = pix;
	float3 Color = 0;
	
	for (int i = -BLUR_ITERATION_; i <= BLUR_ITERATION_; i++)
	{
		int x = abs(i);
		Color += (BLUR_ITERATION_ - x)*tex2D( sTexRim, texcoord + float2(( p.r * ( ( 2 * i ) + 0.5 )), 0)).rgb;	
	}
	return Color/((BLUR_ITERATION_*BLUR_ITERATION_));	
}

float3 VBlur(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
	float2 p = pix;
	float3 Color;
	float3 Bloom;
	float3 Background = tex2D(sTexColor, texcoord).rgb;
	float Depth = ReShade::GetLinearizedDepth(texcoord);
	
	for (int i = -BLUR_ITERATION_; i <= BLUR_ITERATION_; i++)
	{
		int x = abs(i);
		Color += (BLUR_ITERATION_ - x)*tex2D( sTexHBlur, texcoord + float2(0,( p.g * ( ( 2 * i ) + 0.5 )))).rgb;	
	}
	Bloom = Color/((BLUR_ITERATION_*BLUR_ITERATION_));
	
	Bloom *= bloom;
	Bloom += tex2D( sTexRim, texcoord).rgb;
	Bloom = saturate(Bloom);
	float3 Mixed;
	if(Blend == 0) Mixed = Bloom + Background;
	if(Blend == 1) Mixed = Background / ( 1 - Bloom );
	
	Mixed = lerp(Background, Mixed, bool ( Depth < MaxDepth && Depth > MinDepth ));
	return Mixed;
	//return GetNormalHQ(texcoord);
}
///////////////Pixel Shader////////////////
///////////////Techniques//////////////////

technique Rim <
	ui_tooltip = "               Rim Light Effect               \n"
				 "               ||By Ehsan2077||               \n"
				 "Add an AO shader after this for a better look.";

>
{
	pass Rim
	{
		VertexShader = PostProcessVS;
		PixelShader = rim;
		RenderTarget = TexRim;
	}
	pass HBlur
	{
		VertexShader = PostProcessVS;
		PixelShader = HBlur;
		RenderTarget = TexHBlur;
	}
	pass VBlur	
	{
		VertexShader = PostProcessVS;
		PixelShader = VBlur;
		//RenderTarget = TexVBlur;
	}
}


///////////////Techniques//////////////////
